package com.dji.sample.media.controller;

import com.alibaba.fastjson2.JSONObject;
import com.dji.sample.common.model.CustomClaim;
import com.dji.sample.common.model.PaginationData;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.common.util.MinioUtil;
import com.dji.sample.component.mqtt.model.MapKeyConst;
import com.dji.sample.component.oss.model.OssConfiguration;
import com.dji.sample.media.model.FileUploadDTO;
import com.dji.sample.media.model.MediaFileDTO;
import com.dji.sample.media.model.MediaFileEntity;
import com.dji.sample.media.service.IMediaService;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.minio.ObjectWriteResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM;

/**
 * @author sean
 * @version 0.2
 * @date 2021/12/7
 */
@Slf4j
@RestController
@RequestMapping("${url.media.prefix}${url.media.version}/workspaces")
public class MediaController {

    @Autowired
    private IMediaService mediaService;

    @Autowired
    MinioUtil minioUtil;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    OssConfiguration ossConfiguration;

    @Value("${oss.domain:}")
    String ossDomain;

    @PostMapping("/upload")
    public ResponseResult uploadMedia(@RequestParam(name = "file") MultipartFile uploadFile, @RequestParam String deviceSn, HttpServletRequest request, @RequestParam(required = false) String fileName) throws IOException {
        CustomClaim customClaim = (CustomClaim) request.getAttribute(TOKEN_CLAIM);
        if (uploadFile == null) {
            return ResponseResult.error("请选择文件");
        }
        String oldName = uploadFile.getOriginalFilename();
        assert oldName != null;
        String newName = StringUtils.hasText(fileName) ? fileName + "_" + deviceSn + oldName.substring(oldName.lastIndexOf(".")) :
                UUID.randomUUID() +
                        oldName.substring(oldName.lastIndexOf("."));
        ObjectWriteResponse objectWriteResponse = minioUtil.upload(newName, uploadFile);
        MediaFileDTO mm = new MediaFileDTO();
        mm.setFileName(newName);
        mm.setFilePath(objectWriteResponse.bucket());
        mm.setObjectKey(objectWriteResponse.object());
        mm.setCreateTime(LocalDateTime.now());
        mm.setFingerprint(objectWriteResponse.etag());
        mm.setTinnyFingerprint(objectWriteResponse.etag());
        mm.setIsOriginal(false);
        mm.setDrone(deviceSn);
        mm.setPayload(deviceSn);
        mm.setDeviceSn(deviceSn);
        mm.setOrgCode(customClaim.getOrgCode());
        mm.setOrgId(customClaim.getOrgId());
        mediaService.save(mm);
        return ResponseResult.success(objectWriteResponse.object());
    }

    @PostMapping("/page")
    public ResponseResult<PaginationData<MediaFileEntity>> page(@RequestParam(required = false) String deviceSn, @RequestParam Long page, @RequestParam Long pageSize, HttpServletRequest request) {
        CustomClaim customClaim = (CustomClaim) request.getAttribute(TOKEN_CLAIM);
        return ResponseResult.success(mediaService.findByDeviceSn(deviceSn, page, pageSize, customClaim.getOrgCode()));
    }

    @GetMapping("getOssUrl")
    public ResponseResult<?> getLine(@RequestParam String ossKey) throws Exception {
        if (StringUtils.hasText(ossDomain)) {
            String url = minioUtil.preview(ossKey);
            stringRedisTemplate.opsForValue().set("oss:" + ossKey, url, ossConfiguration.getExpire(), TimeUnit.SECONDS);
            return ResponseResult.success(ossDomain + "?ossKey=" + ossKey);
        }
        String url = minioUtil.preview(ossKey);
        return ResponseResult.success(url);
    }

    /**
     * Check if the file has been uploaded by the fingerprint.
     *
     * @param workspaceId
     * @param file
     * @return
     */
    @PostMapping("/{workspace_id}/fast-upload")
    public ResponseResult fastUpload(@PathVariable(name = "workspace_id") String workspaceId, @RequestBody FileUploadDTO file) {

        boolean isExist = mediaService.fastUpload(workspaceId, file.getFingerprint());

        return isExist ? ResponseResult.success() : ResponseResult.error(file.getFingerprint() + "don't exist.");
    }

    /**
     * When the file is uploaded to the storage server by pilot,
     * the basic information of the file is reported through this interface.
     *
     * @param workspaceId
     * @param file
     * @return
     */
    @PostMapping("/{workspace_id}/upload-callback")
    public ResponseResult<String> uploadCallback(@PathVariable(name = "workspace_id") String workspaceId, @RequestBody FileUploadDTO file) {
        mediaService.saveMediaFile(workspaceId, file);
        log.info("==uploadCallback=={}", JSONObject.toJSONString(file));
        return ResponseResult.success(file.getObjectKey());

    }

    /**
     * Query the files that already exist in this workspace based on the workspace id and the collection of tiny fingerprints.
     *
     * @param workspaceId
     * @param tinyFingerprints There is only one tiny_fingerprint parameter in the body.
     *                         But it is not recommended to use Map to receive the parameter.
     * @return
     */
    @PostMapping("/{workspace_id}/files/tiny-fingerprints")
    public ResponseResult<Map<String, List<String>>> uploadCallback(
            @PathVariable(name = "workspace_id") String workspaceId,
            @RequestBody Map<String, List<String>> tinyFingerprints) throws JsonProcessingException {

        List<String> existingList = mediaService.getExistTinyFingerprints(workspaceId, tinyFingerprints.get(MapKeyConst.TINY_FINGERPRINTS));
        return ResponseResult.success(new ConcurrentHashMap<>(Map.of(MapKeyConst.TINY_FINGERPRINTS, existingList)));
    }

}